﻿using System;
using System.Windows;
using System.Windows.Markup;
using System.Xml;

namespace AppDesigner.XamlDom
{
    /// <summary>
    /// 这个类为TypeConvert.ConvertFromString(ITypeConvertContext-->提供context 的 ServiceProvider)
    /// </summary>
    public class XamlTypeResolverProvider : IXamlTypeResolver,IServiceProvider
    {
        #region Fields

        private XamlDocument _document;
        private XamlObject _containingObject;

        #endregion

        #region Constructor

        public XamlTypeResolverProvider(XamlObject containingObject)
        {
            if (containingObject == null)
            {
                throw new ArgumentNullException("containingObject");
            }
            _document = containingObject.OwnerDocument;
            _containingObject = containingObject;
        }

        #endregion

        #region Property

        XmlElement ContainingElement
        {
            get
            {
                return _containingObject.XmlElement;
            }
        }

        #endregion

        #region Implements

        public object GetService(Type serviceType)
        {
            if (serviceType == typeof(IXamlTypeResolver) || serviceType == typeof(XamlTypeResolverProvider))
            {
                return this;
            }
            else
            {
                return _document.ServiceProvider.GetService(serviceType);
            }
        }

        public Type Resolve(string qualifiedTypeName)
        {
            string typeNamespaceUri;
            string typeLocalName;

            if (qualifiedTypeName.Contains(":"))
            {
                typeNamespaceUri = ContainingElement.GetNamespaceOfPrefix(qualifiedTypeName.Substring(0, qualifiedTypeName.IndexOf(':')));
                typeLocalName = qualifiedTypeName.Substring(qualifiedTypeName.IndexOf(':') + 1);
            }
            else
            {
                typeNamespaceUri = ContainingElement.GetNamespaceOfPrefix("");
                typeLocalName = qualifiedTypeName;
            }
            if (string.IsNullOrEmpty(typeNamespaceUri))
            {
                throw new InvalidOperationException("UnRecognized namespace prefix in type " + qualifiedTypeName);
            }
            return XamlTypeFinder.GetClrType(typeNamespaceUri,typeLocalName);
        }

        public XamlPropertyInfo ResolveProperty(string propertyName)
        {
            string propertyNamespace;
            if (propertyName.Contains(":"))
            {
                propertyNamespace = ContainingElement.GetNamespaceOfPrefix(propertyName.Substring(0, propertyName.IndexOf(':')));
                propertyName = propertyName.Substring(propertyName.IndexOf(':') + 1);
            }
            else
            {
                propertyNamespace = ContainingElement.GetNamespaceOfPrefix("");
            }

            Type elementType = null;
            XamlObject obj = _containingObject;
            while (obj != null)
            {
                Style style = obj.Instance as Style;
                if (style != null && style.TargetType != null)
                {
                    elementType = style.TargetType;
                    break;
                }
                obj = obj.ParentObject;
            }
            if (propertyName.Equals("."))
            {
                return XamlParser.Instance.GetPropertyInfo(null, elementType, propertyNamespace, propertyName);
            }
            else if (elementType != null)
            {
                return XamlParser.Instance.FindProperty(null, elementType, propertyName);
            }
            else
            {
                return null;
            }
        }

        public object FindResource(object key)
        {
            XamlObject obj = _containingObject;
            while (obj != null)
            {
                FrameworkElement el = obj.Instance as FrameworkElement;
                if (el != null)
                {
                    object val = el.Resources[key];
                    if (val != null)
                    {
                        return val;
                    }
                }
                obj = obj.ParentObject;
            }
            return null;
        }
        #endregion


    }
}
